extern crate tun_tap;
use   std::io;
use  std::collections::HashMap;
use std::net::Ipv4Addr;
mod tcp;


#[derive(Clone,Copy,Hash,Eq,PartialEq)]
struct Quad{
    src_ip: (Ipv4Addr,u16),
    dst_ip: (Ipv4Addr,u16),
}
fn main() -> io::Result<()> {
    let mut connections : HashMap<Quad,tcp::State> = Default::default();
    let nic = tun_tap::Iface::new("tun0",tun_tap::Mode::Tun).expect("failed to cr");
    let mut buf = [0u8;1500];
     loop {
        let nbytes = nic.recv(&mut buf[..])?;
        let flags = u16::from_be_bytes([buf[0],buf[1]]);
        let proto = u16::from_be_bytes([buf[2],buf[3]]);
        // if proto != 0x0800 {
        //     continue;
        // }
        match etherparse::Ipv4HeaderSlice::from_slice(&buf[4..nbytes]){
                Ok(iph) =>{
                        let src = iph.source_addr();
                        let dst = iph.destination_addr();
                        if iph.protocol() != 0x06{
                            continue;
                        }

                        eprintln!("ok---1");
                        match etherparse::TcpHeaderSlice::from_slice(&buf[4 + iph.slice().len()..nbytes]){
                            Ok(tcph) => {
                                let datai = 4 + iph.slice().len() + tcph.slice().len();
                                eprintln!("ok---2");
                                connections.entry(Quad {
                                    src_ip: (src,tcph.source_port()),
                                    dst_ip: (dst,tcph.destination_port()),
                                }).or_default().on_packet(iph,tcph,&buf[datai..nbytes]);
                                // eprintln!("{} -> {}b of tcp to port {}",src,dst,tcph.destination_port())
                                
                            }
                            Err(e) => {
                                eprintln!("ok---3");
                                eprintln!("ignoring weird tcp packet {:?}",e);
                            }
                        }

                        // eprintln!("{} -> {} {}b protocol {:x}",
                        //     src,
                        //     dst,
                        //     iph.payload_len(),
                        //     proto,
                        // );  
                }
                Err(e) => {
                    eprintln!("ignoring weird packet {:?}",e);
                }
            }
        }


        
    Ok(())
}
